Skip to content

feat(cli): detect more agent runtimes in telemetry - #7423

Merged
jrusso1020 merged 5 commits into
mainfrom
agent-runtimes-more
Nov 9, 2026
Merged

jrusso1020 merged 5 commits into
mainfrom
agent-runtimes-more

Conversation

@jrusso1020

@jrusso1020 jrusso1020 commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

What

The CLI telemetry agent detector now recognizes more coding agents and has a generic AI_AGENT fallback:

  • Copilot rule fixed: the old copilot_agent rule keyed on COPILOT_AGENT_ID / RUNNER_NAME=Copilot inside GitHub Actions, and those markers don't appear in any upstream source. It now matches what VS Code actually sets on agent terminals: COPILOT_AGENT=1 or AI_AGENT=github_copilot_*.
  • New rules: copilot_cli, kilo, opencode, qwen_code, junie, antigravity, qoder, kiro, openhands.
  • AI_AGENT fallback: runs after every vendor rule. Known names (claude-code, opencode, crush, pi, hermes) map to their runtime, matching exactly or as a <name>_ prefix. Any other slug-safe value becomes other_ai_agent, and its discovery hints are still sent so it can be promoted to a rule later.
  • Agents seen in our own discovery hints (second commit): closed-source agents with no public marker, where the key shows up in this CLI's agent_env_hints on non-interactive runs. That is direct evidence the key is in the env of the shell the agent spawned. New runtimes: workbuddy, codebuddy, trae, pippit, doubao, aily, grok, kimi, zcode, swe_agent, and claude_agent_sdk (an app built on the Claude Agent SDK, running outside Claude Code's own shell tool). Qoder also matches its CLI and agent SDK keys. Only key presence is checked; several of these values are tokens and are never read. App-wide settings (Qoder's SDK and spawn-depth keys, CODEBUDDY_AGENT_RUNTIME) were left out after review.
  • Agent names: the name map now covers names agents report (Devin, Amp, v0, Rovo Dev, Base44, Trae, Antigravity, OpenHands, Copilot, hermes-agent), matching on a _ or - boundary. A known name in the bare AGENT variable counts too; unknown AGENT values such as AGENT=1 still do not.
  • DeepSeek harness: dsh, from DSH_SHELL=1 (deepseek-ai/deepseek-harness).
  • CI: AWS CodeBuild (CODEBUILD_BUILD_ID) is detected as codebuild.
  • Fewer false hint keys: AGENT_TOOLSDIRECTORY (the GitHub runner toolcache path), GSM_SKIP_SSH_AGENT_WORKAROUND and EDGE_METRICS_SESSION_ID only matched the hint pattern by accident and no longer count as hint keys.
  • agent_hint order: it now prefers AI_AGENT over AGENT, because opencode-style agents set AGENT=1 next to their real name.

Why

Agents with no rule fall into the agent_runtime = null bucket, together with plain shells. Discovery hints from recent CLI versions show markers for several of these agents. The first commit's rules meet the existing bar: the agent's own source or docs say the marker is set in the environment of the shell it spawns. The second commit's rules use the CLI's discovery hints as that evidence instead, since those agents are closed source.

Related work

None found.

How

  • Rule order: first match wins, and the closest agent should win.
    • Markers that are inherited or only say where a shell runs come after every other agent rule: Copilot's COPILOT_AGENT / AI_AGENT and COPILOT_CLI, OpenHands' AI_AGENT, the Agent SDK version key, and the editor/workspace markers (TERM_PROGRAM=cursor|windsurf, Replit). So opencode or Qwen started by Copilot, or Kilo in a Cursor terminal, report as themselves. Cursor's own agent (CURSOR_AGENT) keeps its early slot.
    • copilot_cli comes before copilot_agent, because the CLI run from a VS Code agent terminal inherits COPILOT_AGENT=1.
    • kilo comes before opencode, because Kilo is an opencode fork and its bash tool also sets OPENCODE=1.
  • DeepSeek harness: keys on DSH_SHELL=1 only. dsh also sets DSH_SESSION_ID on the interactive terminal a person types into, so that key would count a person as an agent.
  • Kiro: detection uses AGENT_DISPLAY_OUT / AGENT_CONTEXT_OUT, which are only set while the agent is driving. It does not use TERM_PROGRAM=kiro, which Kiro also sets on a person's terminal.
  • isAgentDriven: also returns true when AI_AGENT is set.
  • Rejected agents: the "deliberately NOT added" block lists markers seen only in bundles or third-party detector packages (Augment, Factory, Windsurf Cascade, Jules, Grok's GROK_AGENT, Trae's TRAE_AI_SHELL_ID).

Test plan

  • Unit tests added/updated: rule ordering (kilo vs opencode, copilot_cli vs copilot_agent, cursor inside a Copilot terminal), AI_AGENT prefix matching (pi does not match pilot), the other_ai_agent hints path, CodeBuild CI, the dropped hint keys, each discovery-hint rule, WorkBuddy over CodeBuddy, vendor markers over the Agent SDK key, and known vs unknown bare AGENT values.
  • vitest run src/telemetry src/utils/attendedTerminal.test.ts: 457/457. The full cli unit and spawn projects pass.
  • bun run lint, oxfmt --check, tsc --noEmit, comment-citation and comment-ratchet checks pass.
  • Manual testing performed
  • Comments follow CONTRIBUTING.md "Comments"

— Rames

🤖 Generated with Claude Code

Agent runtime rules:
- copilot_agent: key on COPILOT_AGENT=1 or AI_AGENT=github_copilot_*
  (VS Code agent terminals) instead of the unverified Actions markers.
- copilot_cli: COPILOT_CLI=1 or COPILOT_AGENT_SESSION_ID, ahead of
  copilot_agent.
- kilo (KILO=1, KILOCODE_VERSION), ahead of opencode.
- opencode (OPENCODE=1, OPENCODE_SESSION_ID).
- qwen_code (QWEN_CODE=1), junie (JUNIE_SHIM_PATH),
  antigravity (ANTIGRAVITY_AGENT), qoder (QODER_AGENT),
  kiro (AGENT_DISPLAY_OUT, AGENT_CONTEXT_OUT), openhands (AI_AGENT=openhands).
- AI_AGENT fallback after every vendor rule: known names map to their
  runtime, any other slug-safe name becomes other_ai_agent. Bare AGENT
  is not used.

Discovery hints: other_ai_agent keeps its hints, agent_hint prefers
AI_AGENT over AGENT, and AGENT_TOOLSDIRECTORY,
GSM_SKIP_SSH_AGENT_WORKAROUND and EDGE_METRICS_SESSION_ID are no
longer hint keys.

CI: name AWS CodeBuild (CODEBUILD_BUILD_ID) as codebuild.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 106 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

jrusso1020 and others added 3 commits November 9, 2026 01:00
Add rules for closed-source agents whose markers show up in the CLI's
own agent_env_hints on non-interactive runs: WorkBuddy, CodeBuddy, Trae,
Pippit, Doubao, Aily, Grok, Kimi, ZCode, SWE-agent and apps built on the
Claude Agent SDK. Qoder also matches its CLI and agent SDK keys.

The AI_AGENT name map now covers the names agents report (Devin, Amp,
v0, Rovo Dev, Base44, Trae, Antigravity, OpenHands, Copilot, and
hermes-agent), and a known name in the bare AGENT variable counts too.
Unknown AGENT values such as AGENT=1 still do not.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every dsh model shell call runs with DSH_SHELL=1 and the agent's
DSH_SESSION_ID. HyperFrames Desktop also runs dsh; its runs carry
HYPERFRAMES_CLIENT, so the client field separates the two.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 2 important · 2 nits · head 46dfccb0a

The DSH_SESSION_ID arm counts a person in DSH's interactive terminal as an agent, and because isAgentDriven now uses it, the CLI stops prompting there. Details are inline. AGENT=1 still returns null, and the _/- boundary checks out.

Scope

I read agent_runtime.ts and system.ts end to end and checked the tests against them. I checked each marker against upstream source where one exists: ZCode, the Grok Build changelog, DSH, and the Claude Agent SDK. Where none exists, I used third-party detectors and public env dumps. CI on this head was still running when I posted.

— Genesis (Claude)

Copilot's COPILOT_AGENT / AI_AGENT and COPILOT_CLI pass down to the
agents it starts, and TERM_PROGRAM / REPL_ID only say where a shell runs.
Those rules now come after every other agent rule, so opencode or Qwen
started by Copilot, or Kilo in a Cursor terminal, report as themselves.

dsh keys on DSH_SHELL=1 only: it sets DSH_SESSION_ID on the terminal a
person types into too. Qoder drops its app-wide SDK and setting keys,
CodeBuddy drops CODEBUDDY_AGENT_RUNTIME (a setting it reads), and Kiro's
markers must be non-empty.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 1 important · 0 nits — 5 resolved, 0 open, 1 new · 46dfccb0a → ccde5935e

— Genesis (Claude)

// not that an agent drives it, so every agent marker above wins over them.
// Cursor's TERM_PROGRAM identifies the IDE terminal only.
// Source: https://docs.cursor.com/en/agent/terminal
{ name: "cursor", check: (env) => env["TERM_PROGRAM"] === "cursor", agentOnly: () => false },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

important: an agent identified only through AI_AGENT/AGENT still loses to these editor and workspace rules, because aiAgentFallback runs after all of VENDOR_RULES. Probed on this head: AI_AGENT=amp + TERM_PROGRAM=cursor → cursor, AI_AGENT=devin_1_agent + REPL_ID → replit, and an unknown AI_AGENT in Cursor → cursor. The last one also drops the discovery hints, since system.ts only sends them for null/other_ai_agent. Suggested fix: split the trailing cursor/windsurf/replit entries into a separate list that detectAgentRuntime checks after aiAgentFallback, and add a test for Amp in Cursor.

@jrusso1020
jrusso1020 added this pull request to the merge queue Nov 9, 2026
Merged via the queue into main with commit c14f258 Nov 9, 2026
130 of 131 checks passed
@jrusso1020
jrusso1020 deleted the agent-runtimes-more branch November 9, 2026 01:57
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 9, 2026
…red-row line counts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@miguel-heygen miguel-heygen mentioned this pull request Nov 9, 2026
3 of 4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant